/*
 * mapa.h
 *
 *  Created on: 07/01/2011
 *      Author: julian
 */

#ifndef MAPA_H_
#define MAPA_H_

#include <list>
#include <vector>
#include "superficierev.h"
#include "bscerrada.h"
#include "bezier.h"
#include "iobmp.h"
#include "textura.h"
#include "discretizador.h"
#include "texels.h"
#include "roca.h"
#include "terreno.h"
#include "perlin.h"
#include "heightfield.h"
#include "relieve.h"

using namespace std;

class Mapa {
private:
	list<Superficie*>* almacenSuperficies;
	list<Roca*>* almacenRocas;
	list<BsplineCerrada*>* revoluciones;
	Bezier* perfil;
	Textura* texturaRoca;
        Terreno *terreno;
	int w;
	int h;

        Perlin generador;  //Ruido para las rocas y el piso
        Perlin generadorRoca;
        Discretizador d;
        Discretizador discrTerreno;
        HeightField hf;

public:
	Mapa(int w, int h) :
           almacenSuperficies(0),
           almacenRocas(0),
           revoluciones(0),
           perfil(0),
           texturaRoca(0),
           terreno(0),
           generador(0.3),
           generadorRoca(2.9),
           //Para que se vea bien, dado que HeightField no hace un promedio de z,
           //la discretizacion debe ser exacta (coincidir en cada vertice del HeightField)
           discrTerreno(1.0/(w), 1.0/(h)),
           hf(w+1, h+1, 0.5, generador)
   {
		this->w = w;
		this->h = h;
		this->almacenSuperficies = new list<Superficie*>();
		this->almacenRocas = new list<Roca*>();
		this->revoluciones = new list<BsplineCerrada*>();
		this->perfil = NULL;
	}

	void setTexturaRoca(Textura* tex){
		this->texturaRoca = tex;
	}
	void setTexturaSuelo(Textura* tex){
		this->terreno = new Terreno(*tex, hf, discrTerreno);
	}

	void establecerPerfil(Bezier* nuevoPerfil){
		this->perfil = nuevoPerfil;
	}

	list<Superficie*>* getAlmacenSuperficies(){
		return this->almacenSuperficies;
	}

	list<Roca*>* getAlmacenRocas(){
		return this->almacenRocas;
	}

	void agregarRevolucion(BsplineCerrada* revolucion){
		this->revoluciones->push_back(revolucion);
                SuperficieRevolucion *supRev = new SuperficieRevolucion(
                      *revolucion,
                      *perfil);
                Superficie* nuevaSup = new Relieve(
                      generadorRoca, *supRev,
                      100, 40,
                      1, 1);


                this->almacenSuperficies->push_back(nuevaSup);
                Roca* nuevaRoca = new Roca(*texturaRoca, *nuevaSup, 
                      supRev->revolucion(),
                      supRev->altura(), d);
                this->almacenRocas->push_back(nuevaRoca);
        }

        void removerObstaculos() {
           list<BsplineCerrada*>::iterator it;
           list<Roca*>::iterator it3;
           for ( it=revoluciones->begin() ; it != revoluciones->end(); it++ )
              delete *it;
           for ( it3=almacenRocas->begin() ; it3 != almacenRocas->end(); ++it3)
              delete *it3;
           this->revoluciones->clear();
           this->almacenRocas->clear();
        }

        int ancho(){
           return w;
        }

        int alto(){
           return h;
        }

        void dibujarSuelo(){
           glPushMatrix();
           glTranslatef(0, 0, -this->hf.minHeight());

           this->terreno->dibujar();

           glPopMatrix();
        }

        void dibujarMiniMapa(){
           glPushAttrib(GL_ALL_ATTRIB_BITS);

           list<BsplineCerrada*>::iterator itsup;
           float paso = 0.05;
           //Dibujado de las curvas
           for ( itsup=revoluciones->begin() ; itsup != revoluciones->end(); itsup++ ){
              glBegin(GL_LINE_STRIP);
              glColor3f(1.0,1.0,1.0);
              for(float i=0.0; i<=1; i+=paso){
                 Coord v = (*itsup)->operator ()(i);
                 float normX = v.x()/(this->w);
                 float normY = v.y()/(this->h);
                 glVertex2f(normX,normY);
              }
              Coord v = (*itsup)->operator ()(0);
              float normX = v.x()/(this->w);
              float normY = v.y()/(this->h);
              glVertex2f(normX,normY);
              glEnd();
              //Dibujado de los puntos de control
              glPointSize(5);
              glBegin(GL_POINTS);
              glColor3f(1.0,0.0,0.0);
              list<BsplineCerrada*>::iterator itsup2;
              for ( itsup2=revoluciones->begin() ; itsup2 != revoluciones->end(); itsup2++ ){
                 vector<Coord> puntos = (*itsup2)->getPuntosControl();
                 for(unsigned i = 0; i<puntos.size(); i++){
                    Coord coordenadas = puntos[i];
                    float coordX = coordenadas.x()/this->w;
                    float coordY = coordenadas.y()/this->h;
                    glVertex2f(coordX,coordY);
                 }
              }
              glEnd();
           }
           glPopAttrib();
        }

        virtual ~Mapa(){
           list<BsplineCerrada*>::iterator it;
           list<Superficie*>::iterator it2;
           list<Roca*>::iterator it3;

           for ( it=revoluciones->begin() ; it != revoluciones->end(); it++ )
              delete *it;
           for ( it2=almacenSuperficies->begin() ; it2 != almacenSuperficies->end(); it2++ )
              delete *it2;
           for ( it3=almacenRocas->begin() ; it3 != almacenRocas->end(); it3++ )
              delete *it3;

           delete revoluciones;
           delete almacenSuperficies;
           delete almacenRocas;
           delete terreno;
        }
};

#endif /* MAPA_H_ */
